﻿using System;
using System.Collections.Generic;
using System.Data;
using ACompany.OrderProcessing.Infrastructure;
using ACompany.OrderProcessing.Infrastructure.Query;
using NHibernate;
using ACompany.OrderProcessing.Infrastructure.CustomExceptions;

namespace ACompany.OrderProcessing.NHibernateRepository
{
    public abstract class BaseRepository<T> : IRepository<T> where T : IAggregateRoot
    {
        private IUnitOfWork _unitOfWork;

        public void Save(T entity)
        {
            //using (var session = SessionFactory.GetNewSession())
            //{
            //    using (var transaction = session.BeginTransaction())
            //    {
            //        session.SaveOrUpdate(entity);
            //        transaction.Commit();
            //    }
            //}

            //web based

            if (_unitOfWork == null)
            {
                using (ITransaction transaction = SessionFactory.GetCurrentSession().BeginTransaction())
                {
                    SessionFactory.GetCurrentSession().SaveOrUpdate(entity);
                    try
                    {
                        transaction.Commit();
                    }
                    catch (StaleObjectStateException ex)
                    {
                        transaction.Rollback();                        
                        throw new   ConcurrencyException("please reload the screen as changes have been made to entity since first we have loaded it", ex);
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        throw;
                    }

                }
            }
            else
            {
                _unitOfWork.Save(entity);
            }
        }

        public void Remove(T entity)
        {
            //using (var session = SessionFactory.GetNewSession())
            //{
            //    using (var transaction = session.BeginTransaction())
            //    {
            //        session.Delete(entity);
            //        transaction.Commit();
            //    }
            //}

            ////web based version

            if (_unitOfWork == null)
            {
                using (var transaction = SessionFactory.GetCurrentSession().BeginTransaction())
                {
                    SessionFactory.GetCurrentSession().Delete(entity);
                    try
                    {
                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        throw;

                    }
                }
            }
            else
            {
                _unitOfWork.Delete(entity);
            }

        }

        public T FindBy(Guid id)
        {
            //using (var session = SessionFactory.GetNewSession())
            //{
            //    return session.Get<T>(id);
            //}
            //web-based
            return SessionFactory.GetCurrentSession().Get<T>(id);
        }

        public IList<T> FindBy(Query query)
        {
            ICriteria criteria = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));
            return QueryTranslator.GetCriteriFrom(criteria, query).List<T>();
        }

        public IList<T> FindAll()
        {
            //using (ISession session = SessionFactory.GetNewSession())
            //{
            //    ICriteria criteria = session.CreateCriteria(typeof(T));
            //    return criteria.List<T>();
            //}
            var criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));

            return criteriaQuery.List<T>();
        }


        public void Inject(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
    }
}
